/*
 * MyVec.h
 *
 *  Created on: 2020年12月14日
 *      Author: san
 */

#ifndef MYVEC_H_
#define MYVEC_H_

#include <memory>

namespace san {

template <typename T>
class MyVec {
public:
	// 构造函数和析构函数
	MyVec<T>(): element(nullptr), first_free(nullptr), cap(nullptr) {};
	MyVec<T>(const MyVec<T> &item) {
		std::cout << "MyVec<T>(const MyVec<T> &item)" << std::endl;
		auto new_data = alloc_n_copy(item.begin(), item.end());
		element = new_data.first;
		first_free = cap = new_data.second;
	}
	// 重载赋值运算符
	MyVec<T> &operator =(MyVec<T> rhs);
	MyVec<T> &operator =(MyVec<T> &&rhs);
	// 移动构造函数
	MyVec<T>(MyVec<T> &&item) noexcept:
			element(std::move(item.element)), first_free(std::move(item.first_free)), cap(std::move(item.cap))
	{
		std::cout << "MyVec<T>(MyVec<T> &&item)" << std::endl;
		item.element = item.first_free = item.cap = nullptr;
	};
	virtual ~MyVec<T>() { free(); };
	// emplace_back
	template <class... Args> void emplace_back(Args&&...);
	// 容量
	std::size_t capacity() { return cap - element; }
	std::size_t size() { return first_free - element; }
	// 检查和分配空间
	void check_n_alloc() { if (size() >= capacity()) reallocate(); }
	void move_n_alloc(std::size_t capacity);  // 显示的移动重新分配
	std::pair<T*, T*> alloc_n_copy(const T *b, const T *e);
	void reallocate();
	// 释放空间
	void free();
	// 添加，删除元素
	void push_back(const T &);
	void pop_back();
	// swap两个对象
	void swap(MyVec<T> lhs, MyVec<T> rhs);
	// begin/end
	T *begin() const { return element; }
	T *end() const { return first_free; }

private:
	static std::allocator<T> alloc;
	T *element;
	T *first_free;
	T *cap;
};

template <typename T>
std::allocator<T> MyVec<T>::alloc;  // 静态对象使用前必须声明

template <typename T>
MyVec<T> &MyVec<T>::operator =(MyVec<T> rhs)
{
	std::cout << "MyVec<T> &MyVec<T>::operator =(MyVec<T> rhs)" << std::endl;
	swap(*this, rhs);
	return *this;
}

template <typename T>
MyVec<T> &MyVec<T>::operator =(MyVec<T> &&rhs)
{
	std::cout << "MyVec<T> &MyVec<T>::operator =(MyVec<T> &&rhs)" << std::endl;
	// 移动拷贝
	element = std::move(rhs.element);
	first_free = std::move(rhs.first_free);
	cap = std::move(rhs.cap);
}

template <typename T>
template <class... Args> void MyVec<T>::emplace_back(Args&&... items)
{
	check_n_alloc();  // 若空间不足则重新分配
	alloc.construct(first_free++, std::forward<Args>(items)...);
}

template <typename T>
void MyVec<T>::push_back(const T &item)
{
	// 添加元素
	check_n_alloc();
	alloc.construct(first_free++, item);
}

template <typename T>
void MyVec<T>::pop_back()
{
	if (first_free)
		alloc.destroy(--first_free);
}

template <typename T>
void MyVec<T>::free()
{
	std::cout << "void MyVec<T>::free()" << std::endl;
	// 销毁并释放内存
	if (element)
	{
		for (auto p = first_free; p != element;)
		{
			alloc.destroy(--p);
		}
		alloc.deallocate(element, size());  // 这里是capacity()还是size()
	}
}

template <typename T>
void MyVec<T>::reallocate()
{
	// 空间扩容
	auto new_capacity = size() ? 2 * size() : 1;  // 编译通过
	auto new_data = alloc.allocate(new_capacity);

	auto dest = new_data;
	auto elem = element;

	for (size_t i = 0; i < size(); ++i)
		alloc.construct(dest++, std::move(*elem++));  // move显示调用移动构造函数

	// 释放空间
	free();  // 编译通过

	element = new_data;
	first_free = dest;
	cap = element + new_capacity;
}

template <typename T>
void MyVec<T>::move_n_alloc(std::size_t capacity)
{
	// 移动并分配大小为capacity的新空间
	auto new_data = alloc.allocate(capacity);

	auto elem = element;
	auto dest = new_data;

	for (auto p = elem; p != first_free;)
		alloc.construct(dest++, std::move(*elem++));
	free();
	element = new_data;
	first_free = dest;
	cap = element + capacity;
}

template <typename T>
std::pair<T*, T*> MyVec<T>::alloc_n_copy(const  T *b, const T *e)
{
	auto data = alloc.allocate(e - b);
	return { data, std::uninitialized_copy(b, e, data) };
}

template <typename T>
void swap(MyVec<T> lhs, MyVec<T> rhs)
{
	using std::swap;
	swap(lhs.element, rhs.element);
	swap(lhs.first_free, rhs.first_free);
	swap(lhs.cap, rhs.cap);
}

} /* namespace san */

#endif /* MYVEC_H_ */
